关于Canvas图片处理的一二事(上)

  照澄

CanvasRenderingContext2D

CanvasRenderingContext2D 接口提供的 2D 渲染上下文用来绘制 <canvas> 元素,为了获得这个接口的对象,需要在 <canvas> 上调用 getContext() ,并提供一个 '2d' 的参数:

1
2
var $canvas = document.getElementById('canvas');
var context = $canvas.getContext('2d');

关于所有Canvas所有二维操作都在 context 上进行。

图片上传

关于图片上传一般都由 <input id="input" type="file">,通过 var file = $('#input')[0].files[0]; 可以获取到 file 对象。

处理 file 对象可以使用两种处理API,即:

  • FileReader.readAsDataURL()

The readAsDataURL method is used to read the contents of the specified Blob or File. When the read operation is finished, the readyState becomes DONE, and the loadend is triggered. At that time, the result attribute contains the data as a URL representing the file’s data as a base64 encoded string.

from https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsDataURL

1
2
3
4
5
6
7
8
var image = new Image();
var reader = new FileReader();

reader.onload = (e) => {
image.src = e.target.result;
};

reader.readAsDataURL(file);
  • URL.createObjectURL()

The URL.createObjectURL() static method creates a DOMString containing an URL representing the object given in parameter. The URL lifetime is tied to the document in the window on which it was created. The new object URL represents the specified File object or Blob object.

from https://developer.mozilla.org/en/docs/Web/API/URL/createObjectURL

1
var objectURL = URL.createObjectURL(blob);

两者不同在于 FileReader 提供多种文件格式获取的方法,readAsDataURL只是其中一种,createObjectURL 则是简单粗暴获取文件的URL。

图片渲染

drawImage

drawImage可以有三种形式的用法,分别接受不同数量的参数:

1
2
3
ctx.drawImage(image, dx, dy);
ctx.drawImage(image, dx, dy, dWidth, dHeight);
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

具体可以根据下图理解参数含义:

帮助理解的一些注意事项:

  • image 为Image 对象,src 为上传文件生成的Base64格式编码

  • d[…] d: destination 目标画布

  • s[…] s: source 原图片

  • (x, y) 坐标轴,s: 图片选取位置 / d: 绘制初始位置

  • (width, height) s: 图像选取宽高 / d: 映射图像大小

图片上传渲染流程图

本地图片上传通过获取其Base64编码值,赋值到 Image 对象上,通过 canvas 提供的 drawImage API 就可以会绘制到画布上。

像素操作

API

像素操作分为三步,与 canvas 相关的API一个为获取像素API getImageData,另一个为处理像素后返回画布的API putImageData

getImageData

1
ctx.getImageData(sx, sy, sWidth, sHeight);

返回值

一个ImageData 对象,包含canvas给定的矩形图像数据: width / height / data(pixelArray)

1
2
3
4
5
6
7
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.rect(10, 10, 100, 100);
ctx.fill();

console.log(ctx.getImageData(50, 50, 100, 100));
// ImageData { width: 100, height: 100, data: Uint8ClampedArray[40000] }

putImageData

1
2
ctx.putImageData(imagedata, dx, dy);
ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);

imageData 为 canvas ImageData 对象,dirty[...] 等同于 s(ource)[...]

像素操作流程图

ImageData

属性

  • ImageData.data 只读 Uint8ClampedArray 描述了一个一维数组,包含以 RGBA 顺序的数据,数据使用 0 至 255(包含)的整数表示。

  • ImageData.height 只读 无符号长整型(unsigned long),使用像素描述 ImageData 的实际高度。

  • ImageData.width 只读 无符号长整型(unsigned long),使用像素描述 ImageData 的实际宽度。

Imagedata.data 所包含的数据为画布整个图像的所有像素值,一共分为4部分:R,G,B,A。前三个值,红色通道、绿色通道、蓝色通道组成了我们日常所见的颜色,最后为 Alpha 值,表示其颜色透明度。

整个像素操作的流程图如下所示:

滤镜图层

滤镜图层是叠加在原图像上的,总共可以用到一下几个API:

  • CanvasRenderingContext2D.globalAlpha 设置全局画布的透明度值

    ctx.globalAlpha = value;

  • CanvasRenderingContext2D.createLinearGradient 绘制线性渐变

    ctx.createLinearGradient(x0, y0, x1, y1);

    • x0 起点的 x 轴坐标。
    • y0 起点的 y 轴坐标。
    • x1 终点的 x 轴坐标。
    • y1 终点的 y 轴坐标。
  • CanvasRenderingContext2D.createRadialGradient 绘制径向渐变

    ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);

    • x0 开始圆形的 x 轴坐标。
    • y0 开始圆形的 y 轴坐标。
    • r0 开始圆形的半径。
    • x1 结束圆形的 x 轴坐标。
    • y1 结束圆形的 y 轴坐标。
    • r1 结束圆形的半径。
  • CanvasGradient.addColorStop 渐变对象提供多层颜色渲染

    createLinearGradientcreateRadialGradient 都会返回一个 CanvasGradient 对象。它提供一个方法做多层渐变处理:addColorStop(offset, color)

    • offset 0到1之间的值
    • color CSS颜色值

栗子:

  • Code:
1
2
3
4
5
6
7
8
9
10
var $canvas = document.getElementById("canvas");
var ctx = $canvas.getContext("2d");

var gradient = ctx.createRadialGradient(100,100,100,100,100,0);

gradient.addColorStop(0,"white");
gradient.addColorStop(1,"green");

ctx.fillStyle = gradient;
ctx.fillRect(0,0,200,200);
  • Result:

图片合成

图片合成即将添加图层通过 drawImage 绘制在原图像上,如下图所示:

图片导出

图片导出通过 toDataURL API获得当前画布的Base64编码值,可以直接赋值到 Image 对象上展示出来,也可以上传到七牛云获取在线链接后赋值给 <img>,如下图所示:

PlotIt

试玩DEMO

基础调节

基础调节功能的实现依赖 HTML Canvas对图片的像素级处理即位图操作。

基础属性调节是对图片的每一个像素进行遍历处理,通过不同的属性值调节,将图片每一个像素做对应基础处理,即完成基础调节效果。

亮度

亮度的调节原理在于将每个通道的颜色值同时增加或者减少,达到提亮或者变暗的效果。

原理图

结果展示

灰度

灰度的原理在于将所有通道值都设为统一值,综合起来即为灰色。以下每个通道的处理值是经过研究后发现显示灰度效果最合适的值。

原理图

结果展示

添加滤镜

Toaster

这款滤镜首先要绘制一个带两层色彩的径向渐变图层:

通过合成滤镜图层,再做一些基础调节的工作后,滤镜添加完毕:


以上是 Canvas 图片处理,以及 PlotIt 处理原理的简单介绍,后续会添加图片剪裁功能,敬请期待~

END.

分享到